package com.xfdmao.fcat.coin.base.util;

import com.alibaba.fastjson.JSONObject;
import com.xfdmao.fcat.coin.base.constant.KLineConstant;
import com.xfdmao.fcat.coin.base.entity.KlineInfo;
import com.xfdmao.fcat.coin.base.entity.Matrix;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by cissa on 2019/7/28.
 */
public class StrategyUtil {
    /**
     * 找出两条均线最佳的策略
     * @param klineInfos
     */
    public static Matrix queryTwoMaStrategyBest(List<KlineInfo> klineInfos,int maxMA) {
        System.out.println("找出最佳的两条均线值" );
        double [][] mns = new double[maxMA][maxMA];
        boolean [][] top20 = new boolean[maxMA][maxMA];
        for(int m=0;m<maxMA;m++) {
            for (int n = 0; n < maxMA; n++) {
                if(m>=n){
                    List<KlineInfo> result = strategyTwoAvg(klineInfos, m+1, n+1);
                    double income = KlineInfoUtil.getSumIncomeRate(result);
                    if(income>0){
                        mns[m][n] = income;
                    }else{
                        mns[m][n] = 0.0;
                    }
                }else{
                    mns[m][n] = 0.0;
                }

            }
        }
        List<Matrix> matrixList = MatrixUtil.dealMatrix(mns);
        MatrixUtil.print(mns);


        Matrix matrix = MatrixUtil.queryMaxMatrix(mns);
        Integer maxM = matrix.getM();
        Integer maxN = matrix.getN();
        System.out.println("最佳的策略："+ JSONObject.toJSONString(matrix));
        return matrix;
    }


    //找出涨幅大于5%，并且收盘价大于20MA，开盘价小于20MA
    public static void strategyUpDown(List<KlineInfo> klineInfos, Map<Date,Double> avgMap5, Map<Date,Double> avgMap10, Map<Date,Double> avgMap20) {
        System.out.println("左边是上涨百分点，上面是下跌的百分点\n" +
                "例如：[16][9],表示左边序列16（上涨16个点以上买入），右序列为9（下跌9个点以上卖出），总收益为179.11%");
        double p = 0.01;//初始值
        double q = 0.005;//每次递增的值
        double  paramM = p;

        double [][] mns = new double[30][30];
        boolean [][] top20 = new boolean[30][30];
        for(int m=0;m<30;m++) {
            double  paramN = p;
            for (int n = 0; n < 30; n++) {
                mns[m][n] = dealStrategyUpDown(klineInfos, paramM, paramN, avgMap5, avgMap10, avgMap20);
                paramN += q;
            }
            paramM +=q;
        }
        List<Matrix> matrixList = MatrixUtil.dealMatrix(mns);
        MatrixUtil.dealTop20(top20,matrixList);
        Matrix matrix = MatrixUtil.queryMaxMatrix(mns);
        Integer maxM = matrix.getM();
        Integer maxN = matrix.getN();
        MatrixUtil.print(mns);

        System.out.println(String.format("最大收益：%-8.4f\t买入上涨幅度：%-8.4f\t卖出下跌幅度：%-8.4f", dealStrategyUpDown(klineInfos,(maxM+1)*p,(maxN+1)*p, avgMap5, avgMap10, avgMap20),(maxM+1)*p,(maxN+1)*p));
        KlineInfoUtil.printBuySell(klineInfos);
    }



    public static double dealStrategyUpDown(List<KlineInfo> klineInfos, double paramM, double paramN, Map<Date,Double> avgMap5, Map<Date,Double> avgMap10, Map<Date,Double> avgMap20) {
        KlineInfoUtil.init(klineInfos);
        List<KlineInfo> result1 = new ArrayList<>();
        Map<Date, Double> incomeMap = new HashMap<>();
        boolean positionStatus = false;
        for (int i = 0; i < klineInfos.size(); i++) {
            KlineInfo klineInfo = klineInfos.get(i);
            //建仓
            //  if (klineInfo.dealGain() >= paramM && klineInfo.getClose() > avgMap5.get(klineInfo.getDate())) {
                if (klineInfo.getGain() >= paramM ) {
                if (!positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_BUY);
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }
            //平仓
            if (klineInfo.getGain() <= -paramN) {
                if (positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_SELL);
                    klineInfo.setIncomeRate(new BigDecimal(klineInfo.getClose()).subtract(new BigDecimal(result1.get(result1.size() - 1).getClose())).multiply(new BigDecimal(100d)).divide(new BigDecimal(klineInfo.getClose()), 4, BigDecimal.ROUND_DOWN).doubleValue());
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }
        }
        double result = KlineInfoUtil.getSumIncomeRate(klineInfos);
        return result;
    }

    public static void strategyAvgAll(List<KlineInfo> klineInfos) {
        int ma = 1;
        int count = 120;
        List<Double> incomeList = new ArrayList<>();
        for(int i=1;i<=count;i++){
            Map<Date,Double> avgMap =  KlineInfoUtil.getAvg(klineInfos,i);
            List<KlineInfo> result = dealStrategyAvg(klineInfos,avgMap);
            double income = KlineInfoUtil.getSumIncomeRate(result);
            incomeList.add(income);
        }
        KlineInfoUtil.printIncomeList(incomeList);
    }
    public static void strategyAvg(List<KlineInfo> klineInfos, Integer upMaNum) {
        Map<Date,Double> upAvgMap =  KlineInfoUtil.getAvg(klineInfos,upMaNum);
        List<KlineInfo> result = dealStrategyAvg(klineInfos,upAvgMap);
        KlineInfoUtil.print(result,upAvgMap);
        double income = KlineInfoUtil.getSumIncomeRate(result);
        System.out.println("ma"+upMaNum+":"+income);
    }

    public static List<KlineInfo> dealStrategyAvg(List<KlineInfo> klineInfos, Map<Date, Double> upAvgMap) {
        KlineInfoUtil.init(klineInfos);
        List<KlineInfo> result1 = new ArrayList<>();
        Map<Date, Double> incomeMap = new HashMap<>();
        boolean positionStatus = false;
        for (int i = 0; i < klineInfos.size(); i++) {
            KlineInfo klineInfo = klineInfos.get(i);
            if("0.0".equals(upAvgMap.get(klineInfo.getDate()).toString()))continue;
            //建仓
            if (klineInfo.getClose() > upAvgMap.get(klineInfo.getDate()) ) {
                if (!positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_BUY);
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }
            //平仓
            if (klineInfo.getClose() < upAvgMap.get(klineInfo.getDate())) {
                if (positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_SELL);
                    klineInfo.setIncomeRate(new BigDecimal(klineInfo.getClose()).subtract(new BigDecimal(result1.get(result1.size() - 1).getClose())).multiply(new BigDecimal(100d)).divide(new BigDecimal(result1.get(result1.size() - 1).getClose()), 4, BigDecimal.ROUND_DOWN).doubleValue());
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }
        }
        return result1;
    }


    public static List<KlineInfo> strategyTwoAvg(List<KlineInfo> klineInfos, Integer upMaNum, Integer downMaNum) {
        Map<Date,Double> upAvgMap =  KlineInfoUtil.getAvg(klineInfos,upMaNum);
        Map<Date,Double> downAvgMap =  KlineInfoUtil.getAvg(klineInfos,downMaNum);
        List<KlineInfo> result = dealStrategyTwoAvg(klineInfos,upAvgMap,downAvgMap);
        return result;
    }
    private static List<KlineInfo> dealStrategyTwoAvg(List<KlineInfo> klineInfos, Map<Date, Double> upAvgMap, Map<Date, Double> downAvgMap) {
        KlineInfoUtil.init(klineInfos);
        List<KlineInfo> result1 = new ArrayList<>();
        Map<Date, Double> incomeMap = new HashMap<>();
        boolean positionStatus = false;
        for (int i = 0; i < klineInfos.size(); i++) {
            if(i<2)continue;
            KlineInfo klineInfo = klineInfos.get(i);
            if("0.0".equals(upAvgMap.get(klineInfo.getDate()).toString()))continue;
            if((upAvgMap.get(klineInfo.getDate())<downAvgMap.get(klineInfo.getDate()))  && //买入条件： 1、当前收盘K线的长期均线值 小于 短期均线的值
                    upAvgMap.get(klineInfo.getDate())>upAvgMap.get(klineInfos.get(i-1).getDate()) &&  //2、当前收盘K线的长期均线的值  大于  当前收盘K线的长期均线的值       即：长期均线网上走
                    klineInfo.getClose()>downAvgMap.get(klineInfo.getDate()) &&  //3、当前收盘K线的收盘价高于短期均线的收盘价
                    !KlineInfoUtil.isUpperLead(klineInfo) &&  //4、当前收盘K线不能收长的上引线
                    !KlineInfoUtil.isUpperLead(klineInfos.get(i-1)) &&  //5、当前收盘K线的上一个K线不能收上引线
                    klineInfo.getGain()>-0.008 &&  //6、当前收盘K线跌幅不能大于0.8个点
                    klineInfos.get(i-1).getGain()>-0.008 &&  //7、当前收盘K线的上一个K线跌幅不能大于0.8个点
                    !KlineInfoUtil.bigVolDown(klineInfo,klineInfos.get(i-1),klineInfos.get(i-2)) &&   //8、下跌那根K线的量不能是最近三根K线的最大量
                    downAvgMap.get(klineInfo.getDate())>downAvgMap.get(klineInfos.get(i-1).getDate()) && //9、短期均线翻上
                    !KlineInfoUtil.twoDown(klineInfo,klineInfos.get(i-1),klineInfos.get(i-2),downAvgMap) &&  //10、最近三根K线中不能有两根以上的K线下跌或小于均值
                   // klineInfo.getGain() + klineInfos.get(i-1).getGain() < 3 &&//11、当前收盘K线和上一根K线的涨幅不能超过3%
                    //(upAvgMap.get(klineInfo.getDate())- upAvgMap.get(klineInfos.get(i-1).getDate())) > 0.002d &&//12、当前收盘K线的长期均线的值-上一根K线  > 0.0045  (即走平不考虑)
                    //!(klineInfo.getGain()<0 && klineInfos.get(i-1).getGain()>0 && Math.abs(klineInfo.getGain()) >klineInfos.get(i-1).getGain()) &&//13、当前收盘K线的跌幅不能大于上一根K线的涨幅
                    1==1
                    ){ //两条均线价差向上买入&& klineInfo.getClose()>downAvgMap.get(klineInfo.getDate())
                if (!positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_BUY);
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }else if(klineInfo.getClose() < downAvgMap.get(klineInfo.getDate()) ){//卖出条件：1、当前收盘K线的收盘价 小于 当前收盘K线的短期均线的值
                if (positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_SELL);
                    klineInfo.setIncomeRate(new BigDecimal(klineInfo.getClose()).subtract(new BigDecimal(result1.get(result1.size() - 1).getClose())).multiply(new BigDecimal(100d)).divide(new BigDecimal(result1.get(result1.size() - 1).getClose()), 4, BigDecimal.ROUND_DOWN).doubleValue());
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }
        }
        return result1;
    }
 /*   private static List<KlineInfo> dealStrategyTwoAvg(List<KlineInfo> klineInfos, Map<Date, Double> upAvgMap, Map<Date, Double> downAvgMap) {
        KlineInfoUtil.init(klineInfos);
        List<KlineInfo> result1 = new ArrayList<>();
        Map<Date, Double> incomeMap = new HashMap<>();
        boolean positionStatus = false;
        for (int i = 0; i < klineInfos.size(); i++) {
            KlineInfo klineInfo = klineInfos.get(i);
            if("0.0".equals(upAvgMap.get(klineInfo.getDate()).toString()))continue;
            if((upAvgMap.get(klineInfo.getDate())<downAvgMap.get(klineInfo.getDate()))  &&
                    (upAvgMap.get(klineInfos.get(i-1).getDate())>downAvgMap.get(klineInfos.get(i-1).getDate())) &&
                     upAvgMap.get(klineInfo.getDate())>upAvgMap.get(klineInfos.get(i-1).getDate()) &&
                    klineInfo.getClose()>downAvgMap.get(klineInfo.getDate()) &&
                    !KlineInfoUtil.isUpperLead(klineInfo) &&
                    !KlineInfoUtil.isUpperLead(klineInfos.get(i-1)) &&
                    klineInfo.getGain()>-0.01 &&
                    klineInfos.get(i-1).getGain()>-0.01 &&
                    !(klineInfos.get(i).getGain()<0 &&  klineInfos.get(i-1).getGain()<0 &&  klineInfos.get(i-1).getGain()<0) &&
                    1==1
                    ){ //两条均线价差向上买入&& klineInfo.getClose()>downAvgMap.get(klineInfo.getDate())
                if (!positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_BUY);
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }else if(downAvgMap.get(klineInfo.getDate())>klineInfo.getClose() ){//交叉向下卖出
                if (positionStatus) {
                    klineInfo.setBuySellStatus(KLineConstant.BUYSELLSTATUS_SELL);
                    klineInfo.setIncomeRate(new BigDecimal(klineInfo.getClose()).subtract(new BigDecimal(result1.get(result1.size() - 1).getClose())).multiply(new BigDecimal(100d)).divide(new BigDecimal(result1.get(result1.size() - 1).getClose()), 4, BigDecimal.ROUND_DOWN).doubleValue());
                    result1.add(klineInfo);
                    positionStatus = !positionStatus;
                }
            }
        }
        return result1;
    } */
}
